/**
 * com.chaeron.GPS - An API for access to GPS devices.
 *
 *
 * Copyright (c) 2001, 2002 Chaeron Corporation,
 * All rights reserved.
 * 
 * Chaeron grants you a non-exclusive license to use, modify and re-distribute
 * this program under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version, provided that this copyright notice and 
 * license appear on all copies of the software.
 * 
 * Software is provided "AS IS," without a warranty of any kind. ALL EXPRESS OR
 * IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
 * HEREBY EXCLUDED. THE ENTIRE RISK ARISING OUT OF USING THE SOFTWARE IS ASSUMED
 * BY THE LICENSEE. See the GNU General Public License for more details.
 *
 * CHAERON AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 * LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR DISTRIBUTING SOFTWARE.
 * IN NO EVENT WILL CHAERON OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE,
 * PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL
 * OR PUNITIVE DAMAGES, HOWEVER CAUSED AN REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF CHAERON HAS
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 * @version     1.02
 * @author      Andrzej Jan Taramina, Chaeron Corporation
 *              andrzej@chaeron.com
 */

package com.chaeron.GPS.NMEA;

//***************************************************************************
//*
//*     Imports
//*
//***************************************************************************/

import com.chaeron.GPS.*;
import com.chaeron.GPS.event.*;
import com.chaeron.GPS.exception.*;


//***************************************************************************
//*
//*     NMEAGPSImpl Class definition
//*
//***************************************************************************/

/**
 * The NMEAGPSImpl class implements NMEA protocol-specific functions
 *
 */

public class NMEAGPSImpl extends GPS
{
	
	//***************************************************************************
	//*
	//*     Constant definitions
	//*
	//***************************************************************************/
	
	final static byte			BEGIN_PACKET			= '$';
	final static byte			END_PACKET1				= 13;
	final static byte			END_PACKET2				= 10;
	final static byte			BEGIN_CHECKSUM			= '*';
	final static byte			FIELD_SEPARATOR			= ',';
	
	
	//***************************************************************************
	//*
	//*     Attributes
	//*
	//***************************************************************************/
	
	
	
	//***************************************************************************
	//*
	//*     Constructors
	//*
	//***************************************************************************/
	
	/**
	 * Create an NMEAGPSImpl instance 
	 *
	 */
	
	public NMEAGPSImpl()
	{
		try {
			setSerialBaudRate( 4800 );
		}
		catch( GPSOperationUnavailableException e ) {
		}
	}
	
	
	//***************************************************************************
	//*
	//*     Comm Abstract Methods (implemented/overriden)
	//*
	//***************************************************************************/
	
	/**
	 * Connecting the GPS.  
	 * @throws GPSOperationUnavailableException
	 */
	
	protected void connectingNotify() throws GPSOperationUnavailableException
	{
		
	}
	
	
	/**
	 * Connected the GPS.  
	 */
	
	protected void connectedNotify()
	{
		postGPSEvent( new GPSEvent( GPSEvent.GPS_EVENT_INITIALIZED, null ) );
		postGPSEvent( new GPSEvent( GPSEvent.GPS_EVENT_CAPABILITIES, null ) );
	}
	
	
	/**
	 * Disconnecting the GPS.  
	 */
	
	protected void disconnectingNotify()
	{
		// No need to do anything
	}
	
	
	/**
	 * Disconnected the GPS.  
	 */
	
	protected void disconnectedNotify()
	{
		// No need to do anything
	}
	
	
	/**
	 * Check if a byte is a Begin Packet. 
	 *
	 * @param	chr		byte to be checked
	 * @return			is begin byte?
	 */
	
	protected boolean isBeginPacketByte( byte chr )
	{
		return( chr == BEGIN_PACKET );
	}
	
	
	/**
	 * Check if a byte is a End Packet. 
	 *
	 * @param	chr		byte to be checked
	 * @return			is end byte?
	 */
	
	protected boolean isEndPacketByte( byte chr )
	{
		return( chr == END_PACKET1 );
	}
	
	
	/**
	 * Check if a duplicate End Packet byte should be ignored, that is, treated as an "escape"
	 * sequence to allow embedding of and End Packet byte in the data catalog.  
	 *
	 * @return			ignore duplicate?
	 */
	
	protected boolean ignoreDuplicateEndByte()
	{
		return( false );
	}
	
	
	/**
	 * Inflate (duplicate) End bytes in buffer 
	 *
	 * @param	writeBuffer		buffer to put the inflated data into
	 * @param	buffer			original data
	 * @param	offset			starting point in original data buffer
	 * @param	length			length of original data buffer
	 * @param	maxLen			max length of write buffer
	 * @return					# bytes copied to writeBuffer
	 */
	
	protected int inflateDuplicateEndBytes( byte[] writeBuffer, byte[] buffer, int offset, int length, int maxLen )
	{
		return( 0 );
	}
	
	
	/**
	 * Append a trailing byte after the end byte?  
	 *
	 * @return			append trailing byte?
	 */
	
	protected boolean appendTrailingEndByte()
	{
		return( true );
	}
	
	
	/**
	 * Get the trailing character after the end character?  
	 *
	 * @return			trailing character
	 */
	
	protected byte getTrailingEndByte()
	{
		return( END_PACKET2 );
	}
	
	
	/**
	 * onPacketNotify will be called when a complete packet has been read from the serial port
	 *
	 * @param		packet		byte array for packet
	 * @param		len			number of bytes in packet
	 */
	
	protected void onPacketNotify( byte[] packet, int len )
	{
		NMEASentence		sentence;
		boolean				handled = false;
		
		try {
			sentence = NMEASentence.createInstance( this, packet, len );
			
			if( sentence != null ) {  //Nothing to do?
				if( isEventListened( GPSEvent.GPS_EVENT_NMEA_SENTENCE ) ) {
					postGPSEvent( new GPSEvent( GPSEvent.GPS_EVENT_NMEA_SENTENCE, sentence ) );
				}
				
				sentence.process( this );
			}
		}
		catch( GPSException exception ) {
			postGPSEvent( new GPSEvent( GPSEvent.GPS_EVENT_ERROR, packet.toString(), exception ) );	
		}
	}
	
	
	//***************************************************************************
	//*
	//* 	Accessor Abstract Methods (implemented/overriden)
	//*
	//***************************************************************************/
	
	/**
	 * Get Manufacturer ID
	 *
	 * @return   Manufacturer Id
	 */
	
	public String getManufacturerID()
	{
		return( "NMEA" );
	}
	
	
	/**
	 * Get Product ID
	 *
	 * @return   Product Id
	 */
	
	public int getProductID()
	{
		return( 0 );
	}
	
	
	/**
	 * Get Description
	 *
	 * @return   Description
	 */
	
	public String getDescription()
	{
		return( "Generic NMEA GPS Device" );
	}
	
	
	/**
	 * Get Software Version
	 *
	 * @return   Software Version
	 */
	
	public int getSoftwareVersion()
	{
		return( 183 );
	}
	
	
}
